package edu.calvin.djs32.cs214.interpreters.frontend;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;
import org.norecess.antlr.ANTLRTester;

import edu.calvin.cs214.hobbes2008.ApplicationTIR;
import edu.calvin.cs214.hobbes2008.IdentifierTIR;
import edu.calvin.cs214.hobbes2008.IfTIR;
import edu.calvin.cs214.hobbes2008.IntegerTIR;
import edu.calvin.cs214.hobbes2008.LetTIR;
import edu.calvin.cs214.hobbes2008.StringTIR;
import edu.calvin.cs214.hobbes2008.TupleTIR;


public class Hobbes2008TIRBuilderTest {
	private ANTLRTester myTester;

	@Before
	public void setUp() {
		myTester = new ANTLRTester(new Hobbes2008FrontEnd());
	}
	
	@Test
	public void shouldBuildIntegerTIR() {
	  assertEquals(new IntegerTIR(5), myTester.scanInput("5").parseAs("expression").treeParseAs("expression"));
	  assertEquals(new IntegerTIR(19), myTester.scanInput("19").parseAs("expression").treeParseAs("expression"));
	  assertEquals(new IntegerTIR(0x123f), myTester.scanInput("0x123f").parseAs("expression").treeParseAs("expression"));
	}
	
	@Test
	public void shouldBuildStringTIR(){
		assertEquals(new StringTIR("foo"), myTester.scanInput("'foo'").parseAs("expression").treeParseAs("expression"));
		assertEquals(new StringTIR("bar"), myTester.scanInput("'bar'").parseAs("expression").treeParseAs("expression"));
		assertEquals(new StringTIR("foo bar"), myTester.scanInput("'foo bar'").parseAs("expression").treeParseAs("expression"));
	}
	
	
	@Test
	public void shouldBuildTupleTIR() {
	  assertEquals(new TupleTIR(), myTester.scanInput("()").parseAs("expression").treeParseAs("expression"));
	  assertEquals(new TupleTIR(new IntegerTIR(5)), myTester.scanInput("(5)").parseAs("expression").treeParseAs("expression"));
	  assertEquals(new TupleTIR(new IntegerTIR(5), new IntegerTIR(6), new IntegerTIR(7)), myTester.scanInput("(5, 6, 7)").parseAs("expression").treeParseAs("expression"));
	  assertEquals(new TupleTIR(new IntegerTIR(5), new TupleTIR(new IntegerTIR(6), new IntegerTIR(7))), myTester.scanInput("(5, (6, 7))").parseAs("expression").treeParseAs("expression"));
	  assertEquals(new TupleTIR(new IntegerTIR(5), new StringTIR("foo"), new IntegerTIR(7)), myTester.scanInput("(5, 'foo', 7)").parseAs("expression").treeParseAs("expression"));
	}
	
	@Test
	public void shouldBuildIdentifierTIR(){
		assertEquals(new IdentifierTIR("+"), myTester.scanInput("+").parseAs("identifier").treeParseAs("identifier"));
		assertEquals(new IdentifierTIR("-"), myTester.scanInput("-").parseAs("identifier").treeParseAs("identifier"));
		assertEquals(new IdentifierTIR("/"), myTester.scanInput("/").parseAs("identifier").treeParseAs("identifier"));
		assertEquals(new IdentifierTIR("/"), myTester.scanInput("/").parseAs("expression").treeParseAs("expression"));
	}
	
	@Test
	public void shouldBuildApplicationTIR(){
		assertEquals(new ApplicationTIR(new IdentifierTIR("+"), new TupleTIR(
			    new IntegerTIR(1), new IntegerTIR(2))), myTester.scanInput(
			    "+(1,2)").parseAs("expression").treeParseAs("expression"));
		assertEquals(new ApplicationTIR(new IdentifierTIR("/"), new TupleTIR(
			    new IntegerTIR(1), new IntegerTIR(2))), myTester.scanInput(
			    "/(1,2)").parseAs("expression").treeParseAs("expression"));
		assertEquals(new ApplicationTIR(new IdentifierTIR("/"), new TupleTIR(
			    new IntegerTIR(1), new IntegerTIR(2))), myTester.scanInput(
			    "/(1,2)").parseAs("expression").treeParseAs("expression"));
	}
	
	@Test
	public void shouldBuildIfTIR(){
		assertEquals(new IfTIR(new IntegerTIR(1), new IntegerTIR(2), new IntegerTIR(3)), myTester.scanInput("if 1 then 2 else 3 end").parseAs("expression").treeParseAs("expression"));
		assertEquals(new IfTIR(new IntegerTIR(1), new IfTIR(new IntegerTIR(1), new IntegerTIR(2), new IntegerTIR(3)), new IntegerTIR(3)), myTester.scanInput("if 1 then if 1 then 2 else 3 end else 3 end").parseAs("expression").treeParseAs("expression"));
		assertEquals(new IfTIR(new IntegerTIR(1), new StringTIR("foo"), new IntegerTIR(3)), myTester.scanInput("if 1 then 'foo' else 3 end").parseAs("expression").treeParseAs("expression"));
		assertEquals(new IfTIR(new IntegerTIR(1), new StringTIR("foo"), new StringTIR("bar")), myTester.scanInput("if 1 then 'foo' else 'bar' end").parseAs("expression").treeParseAs("expression"));
	}
	
	@Test
	public void shouldBuildLetTIR(){
		assertEquals(new LetTIR(new IdentifierTIR("x"), new IntegerTIR(5), new IntegerTIR(99)), myTester.scanInput("let x := 5 in 99").parseAs("expression").treeParseAs("expression"));
		assertEquals(new LetTIR(new IdentifierTIR("x"), new IntegerTIR(3), new LetTIR(new IdentifierTIR("y"), new IntegerTIR(2), new ApplicationTIR(new IdentifierTIR("+"), new TupleTIR(new IdentifierTIR("x"), new IdentifierTIR("y"))))), myTester.scanInput("let x := 3 in let y := 2 in +(x,y)").parseAs("expression").treeParseAs("expression"));
		
	}

}
